package org.liveboardgames.agricola.business.updater;

import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.liveboardgames.agricola.business.helper.GameHelper;
import org.liveboardgames.agricola.domain.Change;
import org.liveboardgames.agricola.domain.Game;
import org.liveboardgames.agricola.domain.card.Card;
import org.liveboardgames.agricola.domain.card.ImprovementCard;
import org.liveboardgames.agricola.domain.common.Peep;
import org.liveboardgames.agricola.domain.farm.Farm;
import org.liveboardgames.agricola.domain.farm.FarmTile;
import org.liveboardgames.agricola.model.enums.AlternativeCostEnum;
import org.liveboardgames.agricola.model.enums.BirthStatusEnum;
import org.liveboardgames.agricola.model.enums.ChangesEnum;
import org.liveboardgames.agricola.model.enums.FarmElementEnum;
import org.liveboardgames.agricola.model.enums.ResourceTypeEnum;

public class FarmUpdater extends AbstractUpdater implements IResourceUpdater {

  private Farm farm;

  private Game game;

  /** game can be null, if not needed for a payment for now */
  public FarmUpdater(Game game, Farm farm, List<Change> changes) {
    super(changes);
    this.farm = farm;
    this.game = game;
  }

  public void addPeep(Peep peep) {
    List<FarmTile> tiles = farm.getTiles();

    // Try to fit one peep per tile
    boolean allRoomsFull = true;
    for (Iterator<FarmTile> iterator = tiles.iterator(); iterator.hasNext();) {
      FarmTile farmTile = iterator.next();
      if (FarmElementEnum.isRoom(farmTile.getFarmElement())) {
        if (farmTile.getPeeps() == null || farmTile.getPeeps().size() == 0) {
          addPeep(farmTile, peep);
          allRoomsFull = false;
          break;
        }
      }
    }

    // All rooms full, need to overload a room
    if (allRoomsFull) {
      FarmTile firstTile = tiles.get(0);
      addPeep(firstTile, peep);
    }
  }

  public void addPeep(FarmTile farmTile, Peep peep) {
    new FarmTileUpdater(farmTile, getChanges()).addPeep(peep);
  }

  public void growUpPeeps() {
    List<Peep> peeps = new GameHelper().getPeepsOnFarm(farm);
    for (Iterator<Peep> iterator = peeps.iterator(); iterator.hasNext();) {
      Peep peep = (Peep)iterator.next();
      if (BirthStatusEnum.NEWBORN.equals(peep.getStatus())) {
        peep.setStatus(BirthStatusEnum.ADULT);
        Change change = new Change(ChangesEnum.PEEP, peep);
        addChange(change);
      }
    }
  }

  public void addResource(String resourceType, Integer outputQuantity) {
    Map<String, Integer> resources = farm.getResources();
    if (resources == null) {
      resources = new HashMap<String, Integer>();
      farm.setResources(resources);
    }
    if (resources.get(resourceType) != null) {
      outputQuantity += resources.get(resourceType);
    }
    resources.put(resourceType, new Integer(outputQuantity));
    Change change = new Change(ChangesEnum.FARM_RESOURCES + "_" + farm.getId(), resources);
    addChange(change);
  }

  public void addResources(Map<String, Integer> newResources) {
    if (newResources != null) {
      for (String resource : newResources.keySet()) {
        addResource(resource, newResources.get(resource));
      }
    }
  }

  public void pay(Map<String, Integer> cost) {
    if (cost != null) {
      Set<String> keys = cost.keySet();
      for (String element : keys) {
        if (ResourceTypeEnum.VALUES.contains(element)) {
          payResources(element, cost.get(element));
        }
        else if (AlternativeCostEnum.DISCARD_FIREPLACE.equalsIgnoreCase(element)) {
          discardFireplace();
        }
        else {
          throw new IllegalArgumentException("Cost not supported for element " + element);
        }
      }
    }
  }

  private void discardFireplace() {
    // Remove the fireplace from the farm
    ImprovementCard fireplace = new GameHelper().findFireplace(farm);
    farm.removePlayedCard(fireplace);
    
    // Add it back to the list of improvements in the game
    new GameUpdater(game, this.getChanges()).addMajorImprovement(fireplace);
    
    Change change = new Change(ChangesEnum.REMOVE_PLAYED_CARDS + "_" + farm.getId(), fireplace.getCardId());
    addChange(change);
  }

  private void payResources(String resource, Integer resourceCost) {
    Map<String, Integer> resources = farm.getResources();
    int stock = resources.get(resource);
    int newStock = stock - resourceCost;
    if (newStock < 0) {
      throw new IllegalArgumentException("The player does not have enough resources to pay");
    }
    else {
      resources.put(resource, newStock);
    }
    Change change = new Change(ChangesEnum.FARM_RESOURCES + "_" + farm.getId(), resources);
    addChange(change);
  }

  public void addPlayedCard(Card card) {
    farm.addPlayedCard(card);
    Change change = new Change(ChangesEnum.ADD_PLAYED_CARDS + "_" + farm.getId(), card);
    addChange(change);
  }
}
